#pragma once
 
#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <unistd.h>
#include "thread.hpp"
#include "lockGuard.hpp"
#include "log.hpp"
 
// 定义默认线程数量
const int g_thread_num = 5;
 
// 类模板ThreadPool，代表一个线程池，可以处理不同类型的任务(T)
template <class T>
class ThreadPool
{
public:
    // 获取线程池内部使用的互斥锁
    pthread_mutex_t *getMutex()
    {
        return &lock;
    }
 
    // 判断任务队列是否为空
    bool isEmpty()
    {
        return task_queue_.empty();
    }
 
    // 线程等待条件变量
    void waitCond()
    {
        pthread_cond_wait(&cond, &lock);
    }
 
    // 从任务队列中取出并移除一个任务
    T getTask()
    {
        T t = task_queue_.front();
        task_queue_.pop();
        return t;
    }
 
private:
    // ThreadPool构造函数，初始化线程池，创建指定数量的工作线程
    ThreadPool(int thread_num = g_thread_num) : num_(thread_num)
    {
        pthread_mutex_init(&lock, nullptr);
        pthread_cond_init(&cond, nullptr);
        for (int i = 1; i <= num_; i++)
        {
            threads_.push_back(new Thread(i, &ThreadPool::routine, this));
        }
    }
 
    // 删除拷贝构造函数和赋值操作符，避免线程池实例的拷贝
    ThreadPool(const ThreadPool<T> &other) = delete;
    const ThreadPool<T> &operator=(const ThreadPool<T> &other) = delete;
 
public:
    // 获取线程池的单例实例
    static ThreadPool<T> *getThreadPool(int num = g_thread_num)
    {
        // 使用双重检查锁定模式确保线程安全地初始化单例
        if (nullptr == thread_ptr) 
        {
            // 加锁
            lockGuard lockguard(&mutex);
 
            // 如果在加锁后仍然没有初始化，则创建一个新的线程池实例
            if (nullptr == thread_ptr)
            {
                thread_ptr = new ThreadPool<T>(num);
            }
 
            // 不需要显式解锁，因为lockGuard会在作用域结束时自动解锁
        }
        return thread_ptr;
    }
 
    // 启动线程池中的所有工作线程
    void run()
    {
        for (auto &iter : threads_)
        {
            iter->start();
            // 记录线程启动成功的日志消息
            logMessage(NORMAL, "%s %s", iter->name().c_str(), "启动成功");
        }
    }
 
    // 静态方法，作为工作线程的执行入口
    static void *routine(void *args)
    {
        // 解封装传入的参数
        ThreadData *td = (ThreadData *)args;
        ThreadPool<T> *tp = (ThreadPool<T> *)td->args_;
 
        // 工作线程循环执行，直到收到终止信号
        while (true)
        {
            T task;
            
            // 上锁，同步访问任务队列
            {
                lockGuard lockguard(tp->getMutex());
 
                // 等待非空任务到来
                while (tp->isEmpty())
                    tp->waitCond();
 
                // 从任务队列中取出一个任务
                task = tp->getTask();
            }
 
            // 执行任务
            task(td->name_);
 
            // 这里假设任务完成后会自动重置循环条件，否则需要显式判断是否退出循环
        }
    }
 
    // 将新任务推送到线程池的任务队列中
    void pushTask(const T &task)
    {
        // 加锁，同步访问任务队列
        lockGuard lockguard(&lock);
 
        // 将任务放入队列，并通知条件变量，有一个新的任务可被处理
        task_queue_.push(task);
        pthread_cond_signal(&cond);
    }
 
    // 线程池析构函数，清理所有线程资源
    ~ThreadPool()
    {
        // 确保所有工作线程完成其任务后再销毁
        for (auto &iter : threads_)
        {
            iter->join();
            delete iter;
        }
 
        // 销毁互斥锁和条件变量
        pthread_mutex_destroy(&lock);
        pthread_cond_destroy(&cond);
    }
 
private:
    // 存储工作线程实例的容器
    std::vector<Thread *> threads_;
    
    // 工作线程的数量
    int num_;
 
    // 任务队列，用于存放待执行的任务
    std::queue<T> task_queue_;
 
    // 单例实例指针
    static ThreadPool<T> *thread_ptr;
 
    // 用于保护线程池单例初始化的全局互斥锁
    static pthread_mutex_t mutex;
 
    // 用于控制线程同步的互斥锁
    pthread_mutex_t lock;
 
    // 条件变量，用于实现线程间的通信，如通知工作线程有新任务到来
    pthread_cond_t cond;
};
 
// 初始化静态成员变量
template <typename T>
ThreadPool<T> *ThreadPool<T>::thread_ptr = nullptr;
 
template <typename T>
pthread_mutex_t ThreadPool<T>::mutex = PTHREAD_MUTEX_INITIALIZER;